#include <iostream>
#include <limits>
#include <thread>
#include "VkBundle.h"
#include <GLFW/glfw3.h>
#include "VkHelper.h"
#include "Geometry.h"
#include "Texture.h"
#include "VkRenderer.h"

VkBundle vk;               //vulkan context
#define MAX_FRAMES_COUNT  2 //双缓冲

uint32_t vertex_shader[] = {
        0x07230203,0x00010000,0x0008000a,0x0000001f,0x00000000,0x00020011,0x00000001,0x0006000b,
        0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
        0x0009000f,0x00000000,0x00000004,0x6e69616d,0x00000000,0x0000000d,0x00000012,0x0000001c,
        0x0000001d,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d,0x00000000,
        0x00060005,0x0000000b,0x505f6c67,0x65567265,0x78657472,0x00000000,0x00060006,0x0000000b,
        0x00000000,0x505f6c67,0x7469736f,0x006e6f69,0x00070006,0x0000000b,0x00000001,0x505f6c67,
        0x746e696f,0x657a6953,0x00000000,0x00070006,0x0000000b,0x00000002,0x435f6c67,0x4470696c,
        0x61747369,0x0065636e,0x00070006,0x0000000b,0x00000003,0x435f6c67,0x446c6c75,0x61747369,
        0x0065636e,0x00030005,0x0000000d,0x00000000,0x00050005,0x00000012,0x6f705f61,0x69746973,
        0x00006e6f,0x00050005,0x0000001c,0x65745f76,0x6f6f6378,0x00006472,0x00050005,0x0000001d,
        0x65745f61,0x6f6f6378,0x00006472,0x00050048,0x0000000b,0x00000000,0x0000000b,0x00000000,
        0x00050048,0x0000000b,0x00000001,0x0000000b,0x00000001,0x00050048,0x0000000b,0x00000002,
        0x0000000b,0x00000003,0x00050048,0x0000000b,0x00000003,0x0000000b,0x00000004,0x00030047,
        0x0000000b,0x00000002,0x00040047,0x00000012,0x0000001e,0x00000000,0x00040047,0x0000001c,
        0x0000001e,0x00000002,0x00040047,0x0000001d,0x0000001e,0x00000002,0x00020013,0x00000002,
        0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,0x00000020,0x00040017,0x00000007,
        0x00000006,0x00000004,0x00040015,0x00000008,0x00000020,0x00000000,0x0004002b,0x00000008,
        0x00000009,0x00000001,0x0004001c,0x0000000a,0x00000006,0x00000009,0x0006001e,0x0000000b,
        0x00000007,0x00000006,0x0000000a,0x0000000a,0x00040020,0x0000000c,0x00000003,0x0000000b,
        0x0004003b,0x0000000c,0x0000000d,0x00000003,0x00040015,0x0000000e,0x00000020,0x00000001,
        0x0004002b,0x0000000e,0x0000000f,0x00000000,0x00040017,0x00000010,0x00000006,0x00000002,
        0x00040020,0x00000011,0x00000001,0x00000010,0x0004003b,0x00000011,0x00000012,0x00000001,
        0x0004002b,0x00000006,0x00000014,0x00000000,0x0004002b,0x00000006,0x00000015,0x3f800000,
        0x00040020,0x00000019,0x00000003,0x00000007,0x00040020,0x0000001b,0x00000003,0x00000010,
        0x0004003b,0x0000001b,0x0000001c,0x00000003,0x0004003b,0x00000011,0x0000001d,0x00000001,
        0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003d,
        0x00000010,0x00000013,0x00000012,0x00050051,0x00000006,0x00000016,0x00000013,0x00000000,
        0x00050051,0x00000006,0x00000017,0x00000013,0x00000001,0x00070050,0x00000007,0x00000018,
        0x00000016,0x00000017,0x00000014,0x00000015,0x00050041,0x00000019,0x0000001a,0x0000000d,
        0x0000000f,0x0003003e,0x0000001a,0x00000018,0x0004003d,0x00000010,0x0000001e,0x0000001d,
        0x0003003e,0x0000001c,0x0000001e,0x000100fd,0x00010038
};

uint32_t frag_shader[] = {
        0x07230203,0x00010000,0x0008000a,0x0000003f,0x00000000,0x00020011,0x00000001,0x0006000b,
        0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001,
        0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,0x00000011,0x00000039,0x00030010,
        0x00000004,0x00000007,0x00030003,0x00000002,0x000001c2,0x00040005,0x00000004,0x6e69616d,
        0x00000000,0x00030005,0x00000009,0x00767579,0x00040005,0x0000000d,0x5f786574,0x00000079,
        0x00050005,0x00000011,0x65745f76,0x6f6f6378,0x00006472,0x00040005,0x0000001a,0x5f786574,
        0x00007675,0x00030005,0x0000002a,0x00626772,0x00050005,0x00000039,0x67617246,0x6f6c6f43,
        0x00000072,0x00040047,0x0000000d,0x00000022,0x00000000,0x00040047,0x0000000d,0x00000021,
        0x00000000,0x00040047,0x00000011,0x0000001e,0x00000002,0x00040047,0x0000001a,0x00000022,
        0x00000000,0x00040047,0x0000001a,0x00000021,0x00000001,0x00040047,0x00000039,0x0000001e,
        0x00000000,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016,0x00000006,
        0x00000020,0x00040017,0x00000007,0x00000006,0x00000003,0x00040020,0x00000008,0x00000007,
        0x00000007,0x00090019,0x0000000a,0x00000006,0x00000001,0x00000000,0x00000000,0x00000000,
        0x00000001,0x00000000,0x0003001b,0x0000000b,0x0000000a,0x00040020,0x0000000c,0x00000000,
        0x0000000b,0x0004003b,0x0000000c,0x0000000d,0x00000000,0x00040017,0x0000000f,0x00000006,
        0x00000002,0x00040020,0x00000010,0x00000001,0x0000000f,0x0004003b,0x00000010,0x00000011,
        0x00000001,0x00040017,0x00000013,0x00000006,0x00000004,0x00040015,0x00000015,0x00000020,
        0x00000000,0x0004002b,0x00000015,0x00000016,0x00000000,0x00040020,0x00000018,0x00000007,
        0x00000006,0x0004003b,0x0000000c,0x0000001a,0x00000000,0x0004002b,0x00000015,0x0000001e,
        0x00000001,0x0004002b,0x00000006,0x00000020,0x3f000000,0x0004002b,0x00000015,0x00000028,
        0x00000002,0x00040018,0x0000002b,0x00000007,0x00000003,0x0004002b,0x00000006,0x0000002c,
        0x3f800000,0x0006002c,0x00000007,0x0000002d,0x0000002c,0x0000002c,0x0000002c,0x0004002b,
        0x00000006,0x0000002e,0x00000000,0x0004002b,0x00000006,0x0000002f,0xbe2872b0,0x0004002b,
        0x00000006,0x00000030,0x3ff0d1b7,0x0006002c,0x00000007,0x00000031,0x0000002e,0x0000002f,
        0x00000030,0x0004002b,0x00000006,0x00000032,0x3fbcbfb1,0x0004002b,0x00000006,0x00000033,
        0xbf1240b8,0x0006002c,0x00000007,0x00000034,0x00000032,0x00000033,0x0000002e,0x0006002c,
        0x0000002b,0x00000035,0x0000002d,0x00000031,0x00000034,0x00040020,0x00000038,0x00000003,
        0x00000013,0x0004003b,0x00000038,0x00000039,0x00000003,0x00050036,0x00000002,0x00000004,
        0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003b,0x00000008,0x00000009,0x00000007,
        0x0004003b,0x00000008,0x0000002a,0x00000007,0x0004003d,0x0000000b,0x0000000e,0x0000000d,
        0x0004003d,0x0000000f,0x00000012,0x00000011,0x00050057,0x00000013,0x00000014,0x0000000e,
        0x00000012,0x00050051,0x00000006,0x00000017,0x00000014,0x00000000,0x00050041,0x00000018,
        0x00000019,0x00000009,0x00000016,0x0003003e,0x00000019,0x00000017,0x0004003d,0x0000000b,
        0x0000001b,0x0000001a,0x0004003d,0x0000000f,0x0000001c,0x00000011,0x00050057,0x00000013,
        0x0000001d,0x0000001b,0x0000001c,0x00050051,0x00000006,0x0000001f,0x0000001d,0x00000001,
        0x00050083,0x00000006,0x00000021,0x0000001f,0x00000020,0x00050041,0x00000018,0x00000022,
        0x00000009,0x0000001e,0x0003003e,0x00000022,0x00000021,0x0004003d,0x0000000b,0x00000023,
        0x0000001a,0x0004003d,0x0000000f,0x00000024,0x00000011,0x00050057,0x00000013,0x00000025,
        0x00000023,0x00000024,0x00050051,0x00000006,0x00000026,0x00000025,0x00000000,0x00050083,
        0x00000006,0x00000027,0x00000026,0x00000020,0x00050041,0x00000018,0x00000029,0x00000009,
        0x00000028,0x0003003e,0x00000029,0x00000027,0x0004003d,0x00000007,0x00000036,0x00000009,
        0x00050091,0x00000007,0x00000037,0x00000035,0x00000036,0x0003003e,0x0000002a,0x00000037,
        0x0004003d,0x00000007,0x0000003a,0x0000002a,0x00050051,0x00000006,0x0000003b,0x0000003a,
        0x00000000,0x00050051,0x00000006,0x0000003c,0x0000003a,0x00000001,0x00050051,0x00000006,
        0x0000003d,0x0000003a,0x00000002,0x00070050,0x00000013,0x0000003e,0x0000003b,0x0000003c,
        0x0000003d,0x0000002c,0x0003003e,0x00000039,0x0000003e,0x000100fd,0x00010038
};

CGeometry geometry;
VkYuvTexture *vkYuvTexture;
VkRgbTexture *vkRgbTexture;

GLFWwindow *window;

void init();
void initImages();
void initGeometry();
void updateUniformBuffer(uint32_t currentFrame);
void updateDescriptorSets(uint32_t currentFrame);
void reCreateSwapchain();
void destroy();

void createSwapchainAndResource(){
    VkHelper::createSwapchain(vk.physicalDev, vk.device, vk.surface, vk.work_queue_index, vk.present_queue_index,
                              &vk.swapchainParam,  &vk.swapchainImage, &vk.swapchain);
    CALL_VK(vkGetSwapchainImagesKHR(vk.device, vk.swapchain, &vk.swapchainImage.imageCount, nullptr));
    vk.swapchainImage.images = static_cast<VkImage *>(malloc(sizeof(VkImage) * vk.swapchainImage.imageCount));
    CALL_VK(vkGetSwapchainImagesKHR(vk.device, vk.swapchain, &vk.swapchainImage.imageCount, vk.swapchainImage.images));
    vk.swapchainImage.views = static_cast<VkImageView *>(malloc(sizeof(VkImageView) * vk.swapchainImage.imageCount));
    for(uint32_t i = 0; i < vk.swapchainImage.imageCount; i++){
        VkHelper::createImageView(vk.device, vk.swapchainImage.images[i],
                                  VK_IMAGE_VIEW_TYPE_2D, vk.swapchainParam.format.format, VK_IMAGE_ASPECT_COLOR_BIT, &vk.swapchainImage.views[i]);
    }
    initImages();
    VkHelper::createRenderPass(vk.device, vk.swapchainParam, &vk.renderPass);
    vk.framebufferCount = vk.swapchainImage.imageCount;
    vk.framebuffers = static_cast<VkFramebuffer *>(malloc(sizeof(VkFramebuffer) * vk.framebufferCount));
    VkHelper::createFramebuffer(vk.device, vk.renderPass, vk.swapchainParam.extent.width, vk.swapchainParam.extent.height,
                                vk.framebufferCount, vk.swapchainImage.views, vk.depthImageView, vk.colorImageView, vk.framebuffers);
}

void destroySwapchainAndResource(){
    for (size_t i = 0; i < vk.framebufferCount; i++) {
        vkDestroyFramebuffer(vk.device, vk.framebuffers[i], VK_ALLOC);
    }
    for(uint32_t i = 0; i < vk.swapchainImage.imageCount; i++){
        vkDestroyImageView(vk.device, vk.swapchainImage.views[i], VK_ALLOC);
    }
    free(vk.swapchainImage.views);
    free(vk.swapchainImage.images);
    vkDestroySwapchainKHR(vk.device, vk.swapchain, VK_ALLOC);
}

void reCreateSwapchain(){
    vkDeviceWaitIdle(vk.device);
    Print("Recreate swapchain start.");

    destroySwapchainAndResource();
    createSwapchainAndResource();
}

void init(){
    VkHelper::createInstance(true, &vk.instance, &vk.debugReport);
    CALL_VK(glfwCreateWindowSurface(vk.instance, window, VK_ALLOC, &vk.surface));
    Print("Surface: %p", vk.surface);
    VkHelper::createDevice(&vk);
    vk.swapchainParam.maxSampleCount = VkHelper::getUsableSampleCountBits(vk.physicalDevLimits.framebufferColorSampleCounts);
    Print("Use Sample Count is %d", vk.swapchainParam.maxSampleCount);
    vk.maxFrameCount = MAX_FRAMES_COUNT;
    VkHelper::createCommandPool(vk.device, vk.work_queue_index, &vk.cmdPool);
    createSwapchainAndResource();
    VkHelper::createPipelineCache(vk.device, &vk.pipelineCache);
    VkHelper::createDescriptorSetLayout(vk.device, &vk.descriptorSetLayout);
    VkHelper::createDescriptorPool(vk.device, vk.maxFrameCount, &vk.descriptorPool);
    vk.descriptorSets = static_cast<VkDescriptorSet *>(malloc(sizeof(VkDescriptorSet) * vk.maxFrameCount));
    VkHelper::allocateDescriptorSets(vk.device, vk.maxFrameCount, vk.descriptorPool, vk.descriptorSetLayout, vk.descriptorSets);
    VkHelper::createPipelineLayerout(vk.device, vk.descriptorSetLayout, &vk.pipelineLayout);

    vk.vertexShaderModule = VkHelper::createShaderModule(vk.device, ARRAY_SIZE(vertex_shader), vertex_shader);
    vk.fragShaderModule = VkHelper::createShaderModule(vk.device, ARRAY_SIZE(frag_shader), frag_shader);
    VkHelper::createPipeline(vk.device, vk.pipelineCache, vk.pipelineLayout, vk.renderPass,
                             vk.vertexShaderModule, vk.fragShaderModule, vk.swapchainParam, &vk.graphicPipeline);
    vk.cmdBufferCount = vk.swapchainImage.imageCount;
    vk.cmdBuffers = static_cast<VkCommandBuffer *>(malloc(sizeof(VkCommandBuffer) * vk.cmdBufferCount));
    VkHelper::allocateCommandBuffers(vk.device, vk.cmdPool, vk.cmdBufferCount, vk.cmdBuffers);

    //int geometry, include vertex, texcoord, normal...
    initGeometry();
    vk.imageSemaphores = static_cast<VkSemaphore *>(malloc(sizeof(VkSemaphore) * vk.maxFrameCount));
    vk.presentSemaphores = static_cast<VkSemaphore *>(malloc(sizeof(VkSemaphore) * vk.maxFrameCount));
    vk.fences = static_cast<VkFence *>(malloc(sizeof(VkFence) * vk.maxFrameCount));
    VkSemaphoreCreateInfo semaphoreCreateInfo = {
            .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
            .pNext = nullptr,
            .flags = 0
    };
    VkFenceCreateInfo fenceCreateInfo = {
            .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
            .pNext = nullptr,
            .flags = 0
    };
    for(uint32_t i = 0; i < vk.maxFrameCount; i++){
        CALL_VK(vkCreateSemaphore(vk.device, &semaphoreCreateInfo, VK_ALLOC, &vk.imageSemaphores[i]));
        CALL_VK(vkCreateSemaphore(vk.device, &semaphoreCreateInfo, VK_ALLOC, &vk.presentSemaphores[i]));
        CALL_VK(vkCreateFence(vk.device, &fenceCreateInfo, VK_ALLOC, &vk.fences[i]));
    }
}

void render(uint32_t currentFrame){

    uint32_t imageIndex = 0;
    VkResult rt = vkAcquireNextImageKHR(vk.device, vk.swapchain, std::numeric_limits<uint64_t>::max(),
                                  vk.imageSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
    if(rt == VK_ERROR_OUT_OF_DATE_KHR){
        reCreateSwapchain();
        return;
    } else if (rt != VK_SUCCESS && rt != VK_SUBOPTIMAL_KHR) {
        throw std::runtime_error("failed to acquire swap chain image!");
    }

    //update
    updateUniformBuffer(currentFrame);
    updateDescriptorSets(currentFrame);
    VkClearValue defaultClearValues[] = {
            {
                .color = {0.1f, 0.1f, 0.2f, 1.0f}
            },
            {
                .depthStencil = {1, 0}
            }
    };
    for(uint32_t i = 0; i < vk.cmdBufferCount; i++){
        VkHelper::beginCommandBuffer(vk.cmdBuffers[i], false);
        VkHelper::beginRenderPass(vk.cmdBuffers[i], vk.renderPass, vk.framebuffers[i], ARRAY_SIZE(defaultClearValues), defaultClearValues, vk.swapchainParam.extent);
        VkHelper::bindRenderResource(vk.cmdBuffers[i], vk.pipelineLayout, vk.graphicPipeline, vk.descriptorSets[currentFrame], geometry);
        VkHelper::geometryDraw(vk.cmdBuffers[i], vk.swapchainParam, geometry);
        VkHelper::endRenderPass(vk.cmdBuffers[i]);
        VkHelper::endCommandBuffer(vk.cmdBuffers[i], vk.device, vk.cmdPool, vk.queue, false);
    }

    VkPipelineStageFlags stages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
    VkSubmitInfo submitInfo = {
            .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
            .pNext = nullptr,
            .waitSemaphoreCount = 1,
            .pWaitSemaphores = &vk.imageSemaphores[currentFrame],
            .pWaitDstStageMask = stages,
            .commandBufferCount = 1,
            .pCommandBuffers = &vk.cmdBuffers[imageIndex],
            .signalSemaphoreCount = 1,
            .pSignalSemaphores = &vk.presentSemaphores[currentFrame],
    };
    CALL_VK(vkQueueSubmit(vk.queue, 1, &submitInfo, VK_NULL_HANDLE));//vk.fences[currentFrame]

    VkPresentInfoKHR presentInfo = {
            .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
            .pNext = nullptr,
            .waitSemaphoreCount = 1,
            .pWaitSemaphores = &vk.presentSemaphores[currentFrame],
            .swapchainCount = 1,
            .pSwapchains = &vk.swapchain,
            .pImageIndices = &imageIndex,
            .pResults = nullptr
    };
    rt = vkQueuePresentKHR(vk.queue, &presentInfo);
    if(rt == VK_ERROR_OUT_OF_DATE_KHR){
        reCreateSwapchain();
        return;
    } else if (rt != VK_SUCCESS && rt != VK_SUBOPTIMAL_KHR) {
        throw std::runtime_error("failed to acquire swap chain image!");
    }

    CALL_VK(vkQueueWaitIdle(vk.queue));
}

void destroy(){
    Print("%s", __FUNCTION__);
    vkDeviceWaitIdle(vk.device);

    vkDestroyImageView(vk.device, vk.colorImageView, VK_ALLOC);
    vkDestroyImage(vk.device, vk.colorImage, VK_ALLOC);
    vkFreeMemory(vk.device, vk.colorImageMemory, VK_ALLOC);
    vkYuvTexture->destroy(vk.device);
    vkRgbTexture->destroy(vk.device);
    geometry.destroy(vk.device);
    vkFreeDescriptorSets(vk.device, vk.descriptorPool, vk.maxFrameCount, vk.descriptorSets);
    free(vk.descriptorSets);
    vkDestroyDescriptorPool(vk.device, vk.descriptorPool, VK_ALLOC);
    vkDestroyDescriptorSetLayout(vk.device, vk.descriptorSetLayout, VK_ALLOC);
    for(uint32_t i = 0; i < vk.maxFrameCount; i++){
        vkDestroyFence(vk.device, vk.fences[i], VK_ALLOC);
        vkDestroySemaphore(vk.device, vk.presentSemaphores[i], VK_ALLOC);
        vkDestroySemaphore(vk.device, vk.imageSemaphores[i], VK_ALLOC);
    }
    free(vk.fences);
    free(vk.presentSemaphores);
    free(vk.imageSemaphores);
    for(uint32_t i = 0; i < vk.framebufferCount; i++){
        vkDestroyFramebuffer(vk.device, vk.framebuffers[i], VK_ALLOC);
    }
    vkFreeCommandBuffers(vk.device, vk.cmdPool, vk.cmdBufferCount, vk.cmdBuffers);
    free(vk.cmdBuffers);
    free(vk.framebuffers);
    vkFreeMemory(vk.device, vk.depthImageMemory, VK_ALLOC);
    vkDestroyImage(vk.device, vk.depthImage, VK_ALLOC);
    vkDestroyImageView(vk.device, vk.depthImageView, VK_ALLOC);
    vkDestroySampler(vk.device, vk.depthImageSampler, VK_ALLOC);
    vkDestroyCommandPool(vk.device, vk.cmdPool, VK_ALLOC);
    vkDestroyPipeline(vk.device, vk.graphicPipeline, VK_ALLOC);
    vkDestroyShaderModule(vk.device, vk.fragShaderModule, VK_ALLOC);
    vkDestroyShaderModule(vk.device, vk.vertexShaderModule, VK_ALLOC);
    vkDestroyPipelineLayout(vk.device, vk.pipelineLayout, VK_ALLOC);
    vkDestroyPipelineCache(vk.device, vk.pipelineCache, VK_ALLOC);
    vkDestroyRenderPass(vk.device, vk.renderPass, VK_ALLOC);
    destroySwapchainAndResource();
    vkDestroyDevice(vk.device, VK_ALLOC);
    vkDestroySurfaceKHR(vk.instance, vk.surface, VK_ALLOC);
    vkDestroyInstance(vk.instance, VK_ALLOC);
    glfwDestroyWindow(window);
    glfwTerminate();
}

static void onFramebufferSizeCallback(GLFWwindow *glfWwindow, int width, int height){
    if(width != vk.swapchainParam.extent.width || height != vk.swapchainParam.extent.height){
        reCreateSwapchain();
    }
}

void initImages(){
    vk.swapchainParam.depthFormat = VkHelper::findDepthSupportFormat(vk.physicalDev);
    VkHelper::createImage(vk.physicalDevMemoProps, vk.device, vk.swapchainParam.extent.width, vk.swapchainParam.extent.height, 1,
                          VK_IMAGE_TYPE_2D, vk.swapchainParam.depthFormat, vk.swapchainParam.maxSampleCount, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
                          &vk.depthImage, &vk.depthImageMemory);
    VkHelper::createImageView(vk.device, vk.depthImage, VK_IMAGE_VIEW_TYPE_2D, vk.swapchainParam.depthFormat,
                              VK_IMAGE_ASPECT_DEPTH_BIT, &vk.depthImageView);
    VkHelper::transitionImageLayout(vk.device, vk.cmdPool, vk.queue, vk.depthImage, vk.swapchainParam.depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT,
                                    VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);

    VkFormat colorFormat = vk.swapchainParam.format.format;
    VkHelper::createImage(vk.physicalDevMemoProps, vk.device, vk.swapchainParam.extent.width, vk.swapchainParam.extent.height, 1,
                          VK_IMAGE_TYPE_2D, colorFormat, vk.swapchainParam.maxSampleCount, VK_IMAGE_TILING_OPTIMAL,
                          VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
                          &vk.colorImage, &vk.colorImageMemory);
    VkHelper::createImageView(vk.device, vk.colorImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat,
                              VK_IMAGE_ASPECT_COLOR_BIT, &vk.colorImageView);
    VkHelper::transitionImageLayout(vk.device, vk.cmdPool, vk.queue, vk.colorImage, vk.swapchainParam.depthFormat, VK_IMAGE_ASPECT_COLOR_BIT,
                                    VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
    VkHelper::transitionImageLayout(vk.device, vk.cmdPool, vk.queue, vk.colorImage, vk.swapchainParam.depthFormat, VK_IMAGE_ASPECT_COLOR_BIT,
                                    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}

void initGeometry(){
    geometry.vertices = {
            {{0.5f, 0.5f, 0.0f},/*vertex*/ {1.0f, 0.0f},/*texcoord*/},
            {{0.0f, 0.5f, 0.0f},/*vertex*/ {1.0f, 1.0f},/*texcoord*/ },
            {{0.0f, 0.0f, 0.0f},/*vertex*/ {0.0f, 1.0f},/*texcoord*/ },
            {{0.5f, 0.0f, 0.0f},/*vertex*/ {0.0f, 0.0f},/*texcoord*/ },
    };
    geometry.indices = {
            0, 1, 2, 0, 2, 3
    };
    VkHelper::initGeometryBuffers(vk.physicalDevMemoProps, vk.device, vk.cmdPool, vk.queue, vk.maxFrameCount, geometry);
}

void updateUniformBuffer(uint32_t currentFrame){

}

void updateDescriptorSets(uint32_t currentframe){
    VkDescriptorImageInfo imageInfo1[] = {
            {
                .sampler = vkYuvTexture->cameraImage.yImg.mSampler,
                .imageView = vkYuvTexture->cameraImage.yImg.mImgView,
                .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
            }
    };

    VkDescriptorImageInfo imageInfo2[] = {
            {
                    .sampler = vkYuvTexture->cameraImage.uvImg.mSampler,
                    .imageView = vkYuvTexture->cameraImage.uvImg.mImgView,
                    .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
            }
    };

    VkWriteDescriptorSet writeDescSets[] = {
            {
                .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
                .pNext = nullptr,
                .dstSet = vk.descriptorSets[currentframe],
                .dstBinding = 1,
                .dstArrayElement = 0,
                .descriptorCount = ARRAY_SIZE(imageInfo1),
                .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
                .pImageInfo = imageInfo1
            },
            {
                .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
                .pNext = nullptr,
                .dstSet = vk.descriptorSets[currentframe],
                .dstBinding = 2,
                .dstArrayElement = 0,
                .descriptorCount = ARRAY_SIZE(imageInfo2),
                .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
                .pImageInfo = imageInfo2
            }
    };
    vkUpdateDescriptorSets(vk.device, ARRAY_SIZE(writeDescSets), writeDescSets, 0, nullptr);
}

void VkRenderer::vk_init(GLFWwindow *window, bool isYuv, const std::string &yuvFile, const std::string &rgbFile) {
    ::window = window;
    init();
    initImages();
    initGeometry();
    if(isYuv){
        vkYuvTexture = new VkYuvTexture(yuvFile, 1600, 1600);
    } else {
        vkRgbTexture = new VkRgbTexture(rgbFile, 1600, 1600);
    }
}

void VkRenderer::vk_render(uint32_t currentFrame, uint32_t width, uint32_t height, bool isPlaying) {
    render(currentFrame);
}

void VkRenderer::vk_destroy() {
    destroy();
}